package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.NewsAutoScanService;
import com.heima.apis.article.IArticleClient;
import com.heima.apis.wemedia.IWeMediaClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.aliyun.AliyunConstants;
import com.heima.common.constants.media.WeMediaConstants;
import com.heima.common.exception.LeadNewsException;
import com.heima.model.admin.pojo.AdChannel;
import com.heima.model.admin.pojo.AdSensitive;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.article.pojo.ApAuthor;
import com.heima.model.common.dto.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojo.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Ronaldo
 * @date 2021/8/7
 */
@Service
@Transactional
@Slf4j
public class NewsAutoScanServiceImpl implements NewsAutoScanService {

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private IWeMediaClient weMediaClient;

    @Autowired
    private AdChannelMapper adChannelMapper;

    @Autowired
    private AdSensitiveMapper adSensitiveMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Value("${file.oss.web-site}")
    private String webSite;

    @Override
    @GlobalTransactional
    public void newsAutoScanById(Integer id) {
        //1.准入控制
        //1.1 参数判断
        if (Objects.isNull(id)) {
            throw new LeadNewsException(AppHttpCodeEnum.PARAM_INVALID);
        }
        //1.2根据参数 查询自媒体文章
        WmNews news = weMediaClient.findNewsById(id);
        if (Objects.isNull(news)) {
            throw new LeadNewsException(AppHttpCodeEnum.NOT_FOUND_NEWS);
        }

        //2.处理审核通过 待发布的文章
        //2.1  处理人工审核通过,并且发布时间小于当前时间的自媒体文章
        if (news.getStatus().equals(WmNews.Status.ADMIN_SUCCESS.getCode()) && news.getPublishTime().getTime() < System.currentTimeMillis()) {
            saveArticle(news);
            return;
        }
        //2.2  处理自动审核通过,并且发布时间小于当前时间的自媒体文章
        if (news.getStatus().equals(WmNews.Status.SUCCESS.getCode()) && news.getPublishTime().getTime() < System.currentTimeMillis()) {
            saveArticle(news);
            return;
        }

        //3.对状态为待审核的文章 进行三阶段审核
        if (news.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {

            //3.1 抽取出自媒体文章中  所有的文本 及 图片 用户三阶段审核
            Map textAndImage = extractFromContent(news);

            //3.2  第一阶段审核  自管理敏感词审核  审核通过放行  不通过则修改自媒体文章状态
            boolean sensitiveScanResult = scanSensitives(news, textAndImage.get("text").toString());
            if (BooleanUtils.isFalse(sensitiveScanResult)){
                log.info("第一阶段自管理敏感词审核失败");
                return;
            }

            //3.3  第二阶段审核  阿里云文本审核
            boolean textScanResult = textScan(news,textAndImage.get("text").toString());
            if (BooleanUtils.isFalse(textScanResult)){
                log.info("第二阶段阿里云文本审核失败");
                return;
            }

            //3.4  第三阶段审核  阿里云图片审核
            boolean imageScanResult = imageScan(news, (List<String>)textAndImage.get("image"));
            if (BooleanUtils.isFalse(imageScanResult)){
                log.info("第三阶段阿里云图片审核失败");
                return;
            }

            //4.1  审核通过  判断发布时间 允许则发布  不允许则修改自媒体媒体文章为待发布状态
            if (news.getPublishTime().getTime() > System.currentTimeMillis()){
                news.setStatus(WmNews.Status.SUCCESS.getCode());
                news.setReason("审核通过,待发布");
                weMediaClient.updateNews(news);
            }

            //4.2  发布app文章 并修改自媒体文章为已发布状态
            saveArticle(news);
        }
    }

    /**
     * 第三阶段审核  阿里云图片审核  审核通过放行  不通过则修改自媒体文章状态
     * @param news 自媒体文章
     * @param image 图片
     * @return boolean
     */
    private boolean imageScan(WmNews news, List<String> image) {
        boolean flag = true;

        if (CollectionUtils.isNotEmpty(image)){
            try {
                Map<String,String> map = greenImageScan.imageScan(image);
                String suggestion = map.get("suggestion");
                if (AliyunConstants.SUGGESTION_BLOCK.equals(suggestion)){
                    flag = false;
                    news.setStatus(WmNews.Status.FAIL.getCode());
                    news.setReason("第三阶段阿里云图片审核失败");
                    weMediaClient.updateNews(news);
                }else if (AliyunConstants.SUGGESTION_REVIEW.equals(suggestion)){
                    flag = false;
                    news.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                    news.setReason("第三阶段阿里云图片审核出现不确定因素,需要人工审核");
                    weMediaClient.updateNews(news);
                }
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 第二阶段审核  阿里云文本审核  审核通过放行  不通过则修改自媒体文章状态
     * @param news 自媒体文章
     * @param text 文本内容
     * @return boolean
     */
    private boolean textScan(WmNews news, String text) {
        boolean flag = true;
        if (StringUtils.isNotBlank(text)){
            try {
                Map<String,String> map = greenTextScan.greeTextScan(text);
                String suggestion = map.get("suggestion");
                if (AliyunConstants.SUGGESTION_BLOCK.equals(suggestion)){
                    flag = false;
                    news.setStatus(WmNews.Status.FAIL.getCode());
                    news.setReason("第二阶段阿里云文本审核失败");
                    weMediaClient.updateNews(news);
                }else if (AliyunConstants.SUGGESTION_REVIEW.equals(suggestion)){
                    flag = false;
                    news.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                    news.setReason("第二阶段阿里云文本审核出现不确定因素,需要人工审核");
                    weMediaClient.updateNews(news);
                }
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 第一阶段审核  自管理敏感词审核  审核通过放行  不通过则修改自媒体文章状态
     *
     * @param news 自媒体文章
     * @param text 文本内容
     * @return boolean
     */
    private boolean scanSensitives(WmNews news, String text) {
        boolean flag = true;

        if (StringUtils.isNotBlank(text)){

            List<AdSensitive> sensitiveList = adSensitiveMapper.selectList(Wrappers.<AdSensitive>lambdaQuery().select(AdSensitive::getSensitives));
            List<String> sensitiveStrList = sensitiveList.stream().map(sensitive -> {
                return sensitive.getSensitives();
            }).collect(Collectors.toList());

            SensitiveWordUtil.initMap(sensitiveStrList);

            Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
            if (map.size() > 0){
                flag = false;
                news.setStatus(WmNews.Status.FAIL.getCode());
                news.setReason("第一阶段自管理敏感词审核失败");
                weMediaClient.updateNews(news);
            }
        }
        return flag;
    }

    /**
     * 抽取自媒体文章中的所有文本及图片
     *
     * @param news 自媒体文章
     * @return Map
     */
    private Map extractFromContent(WmNews news) {

        Map<String, Object> textAndImage = Maps.newHashMap();

        //收集文本内容
        StringBuilder text = new StringBuilder();
        //标题
        text.append(news.getTitle());

        //收集图片内容
        List<String> imageList = Lists.newArrayList();

        if (StringUtils.isNotBlank(news.getContent())) {

            List<Map> content = JSON.parseArray(news.getContent(), Map.class);
            for (Map<String, String> map : content) {

                //收集内容中的文本
                if (map.get("type").equals(WeMediaConstants.WM_NEWS_TYPE_TEXT)) {
                    text.append(map.get("value"));
                }
                //收集内容中的图片
                if (map.get("type").equals(WeMediaConstants.WM_NEWS_TYPE_IMAGE)) {
                    String image = map.get("value");
                    if (!image.startsWith(webSite)) {
                        image = webSite + image;
                    }
                    imageList.add(image);
                }
            }
        }


        //收集封面图片
        String images = news.getImages();
        if (StringUtils.isNotBlank(images)) {
            String[] imageArray = images.split(",");
            for (String imageUrl : imageArray) {
                if (!imageUrl.startsWith(webSite)) {
                    imageUrl = webSite + imageUrl;
                }
                imageList.add(imageUrl);
            }
        }

        //图片去重
        imageList = imageList.stream().distinct().collect(Collectors.toList());

        textAndImage.put("text", text.toString());
        textAndImage.put("image", imageList);
        return textAndImage;
    }

    /**
     * 公共方法  保存app文章信息  并更新自媒体文章信息
     *
     * @param news 自媒体文章
     */
    private void saveArticle(WmNews news) {
        //app文章信息准备
        ArticleDto articleDto = new ArticleDto();
        articleDto.setId(news.getArticleId());
        articleDto.setTitle(news.getTitle());
        articleDto.setLayout(news.getType());
        articleDto.setImages(news.getImages());
        articleDto.setLabels(news.getLabels());
        articleDto.setCreatedTime(new Date());
        articleDto.setPublishTime(new Date());
        articleDto.setContent(news.getContent());

        ApAuthor author = articleClient.findAuthorByWmUserId(news.getUserId());
        articleDto.setAuthorId(author.getId().longValue());
        articleDto.setAuthorName(author.getName());

        AdChannel adChannel = adChannelMapper.selectById(news.getChannelId());
        articleDto.setChannelId(adChannel.getId());
        articleDto.setChannelName(adChannel.getName());
        //调用feign 保存app文章的相关信息
        ResponseResult responseResult = articleClient.saveArticle(articleDto);
        if (!responseResult.getCode().equals(HttpStatus.OK.value())) {
            throw new LeadNewsException(AppHttpCodeEnum.SERVER_ERROR);
        }

        //更新自媒体文章
        Long articleId = (Long) responseResult.getData();
        news.setArticleId(articleId);
        news.setStatus(WmNews.Status.PUBLISHED.getCode());
        news.setReason("审核通过,已发布");
        weMediaClient.updateNews(news);
    }
}
